package com.example.demo.chat;
import com.alibaba.fastjson.JSON;
import com.example.demo.entity.Message;
import com.example.demo.config.GetHttpSessionConfig;
import com.example.demo.entity.Order;
import com.example.demo.service.UserService;
import jakarta.servlet.http.HttpSession;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

//每一个客户端都会有一个该类的对象
@ServerEndpoint(value = "/chat/{userId}",configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {
//    @Autowired
//    private UserService userService;
    private String userId;
    private static final Map<String,Session> onlineUsers = new ConcurrentHashMap<>();
    //这个类可以有很多个对象，但是容器只有一个，所以这里的集合是静态的，是一个线程安全的集合
    private static final List<Message> offLineMessages = new ArrayList<Message>();
    //存储离线信息的集合
    private static Set<String> onLineId =new CopyOnWriteArraySet<String>();
    //每次有用户打开连接或者关闭连接的时候记录当前在线的id

    private Session session;
    //因为这个类有很多对象，这个代表的是当前对象的session，这里不能是静态的

    private HttpSession httpSession;

    private static final List<Order> offlineOrderList = new ArrayList<Order>();

    /*
    * 在建立websocket连接后
    * */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId") String userId){
        System.out.println(session.toString());
        this.userId = userId;
        //如果离线信息里面有发送到当前用户id的
        Iterator<Message> iterator = offLineMessages.iterator();
        int index = 0;
        while (iterator.hasNext()){
            //如果存在没有收到的信息，将json对象发送给前端
            Message message = iterator.next();
            System.out.println("toId:"+message.getToId());
            if(message.getToId().equals(userId)){
                //如果储存的未接受信息中有当前用户对应的信息，则发送给该用户
                System.out.println("发送信息给没有登陆的用户");
                try {
                    session.getBasicRemote().sendText(JSON.toJSONString(message));
                    offLineMessages.remove(index);
                    //不能这样：可能会错过下一个。可以先将下标数-1实现
                    index--;
                    //再把remove后当前的这个位置的元素再进行一次判断
                    //这样还是不行的，应该把数组换成map集合其中值为数组
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            index++;
        }

        System.out.println("连接已打开，id:"+session.getId());
        /*
        * 将session对象进行保存
        * 广播,将登陆的用户推送给所有用户*/
        this.session = session;
        System.out.println(userId);
        onlineUsers.put(userId,session);
        onLineId = onlineUsers.keySet();
        System.out.println("连接人数:"+onLineId.size());
    }
    //连接被创建时调用这个方法
    @OnMessage
    public void onMessage(String message){
        //注意这个地方，不能通过pathparam这样的方式传递toid，前端发送信息只有send方法，可以考虑传递一个同类型的message对象
//        ObjectMapper mapper = new ObjectMapper();
//        System.out.println(message);
        //如果要发送的用户不在线，则记录下将要发送给他的信息，如果他登录了，将信息发送给他
        //如果onLinedId中不包含id
        System.out.println(message);
        Message json = JSON.parseObject(message,Message.class);
        String toId = json.getToId();
        Order order ;
        //这个toId通过前端发送的json转成Message对象
        //如果toId不在线，将信息对象存储
        if (!onLineId.contains(toId)){
            System.out.println(toId+"用户未登录");
            offLineMessages.add(new Message(this.userId,toId,json.getMessage(),json.getTimeStamp()));
            System.out.println("储存的未接收信息数:"+offLineMessages.size());
            return;
        }
        //否则，发送给toId
        try {
            System.out.println(onlineUsers.get(toId));
            onlineUsers.get(toId).getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(onLineId.size());

    }
    //收到客户端的信息是调用这个方法
    @OnClose
    public void onClose(Session session){
        onlineUsers.remove(this.userId);
        onLineId = onlineUsers.keySet();
        System.out.println("socketId:"+session.getId()+"已断开连接");
    }
    private void broadcastAllUsers(String message){
        try{
            Set<Map.Entry<String,Session>> entries = onlineUsers.entrySet();
            for(Map.Entry<String,Session> entry :entries){
                //获取所有用户对应的Session对象
                Session session = entry.getValue();
                //发送信息
                session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public boolean isExist(String userId){
        boolean exist = false;
        Set<String> idSet =onlineUsers.keySet();
        for(String id : idSet){
            if (userId.equals(id)){
                exist=true;
                break;
            }
        }
        return exist;
    }
    public Session getSessionById(String id){
        return onlineUsers.get(id);
    }
    public boolean setOfflineOrder(Order order){
        try{
            offlineOrderList.add(order);
        }
        catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
